package com.jasperframework.boot.common.utils;

/**
  * <p>  </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2022/12/12 12:12
  */

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;


/**
 * AES iv 必须为16个字节 128位
 * 注意事项：
 * 1. key 长度 必须为 128/192/256 位
 * 2. iv  长度 必须为 16 字节
 */
public class AesUtil {

    private static final int SECRET_KEY_SIZE = 128;
    private static final String ALGORITHM = "AES";
    private static final String AES_CIPHER_ALGORITHM_PKCS7 = "AES/CBC/PKCS7Padding";
    private static final String AES_CIPHER_ALGORITHM_PKCS5 = "AES/CBC/PKCS5Padding";

    /**
     * AES 加密操作
     * @param content 待加密内容
     * @param keyStr  加密秘钥字符串
     * @param iv      盐值
     * @return 返回Base64转码后的加密数据
     */
    public static String encrypt(String content, String keyStr, String iv) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        // 创建密码器
        Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM_PKCS5);
        int blockSize = cipher.getBlockSize();
        // 根据指定的字符串生成秘钥
        SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
        // 加密
        byte[] result = cipher.doFinal(content.getBytes());
        //通过Base64转码返回
        return BASE64Utils.getEncodeBase64(result);
    }

    /**
     * AES 解密
     * @param encryptText   已加密的base64密文
     * @param keyStr        自定义的秘钥字符串
     * @param iv            盐值
     * @return
     */
    public static String decrypt(String encryptText, String keyStr, String iv) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        //创建解码器
        Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM_PKCS5);
        int blockSize = cipher.getBlockSize();
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyStr.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        // 解析密文
        byte[] byteMi = BASE64Utils.decodeBase64(encryptText);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, zeroIv);
        byte[] decryptedData = cipher.doFinal(byteMi);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    /**
     * 自动生成AES秘钥
     */
    public static String autoGenerateKey() throws NoSuchAlgorithmException {
        // DES算法要求有一个可信任的随机数源
        SecureRandom sr = new SecureRandom();
        // 生成一个DES算法的KeyGenerator对象
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
        kg.init(SECRET_KEY_SIZE, sr);
        // 生成密钥
        SecretKey secretKey = kg.generateKey();
        return BASE64Utils.getEncodeBase64(secretKey.getEncoded()); // base64返回 满足Aes key的长度
    }

    /**
     * 补位运算
     *
     * @param data      需要补位的字节数组
     * @param blockSize 位数
     * @return
     */
    private static byte[] padToBlockSize(byte[] data, int blockSize) {
        int length = data.length;
        int remainder = length % blockSize;
        if (remainder == 0) {
            return data;
        }
        int newSize = length + blockSize - remainder;
        int paddingLength = blockSize - length % blockSize;
        StringBuilder paddedString = new StringBuilder(new String(data));
        for (int i = 0; i < paddingLength; i++) {
            paddedString.append((char) 0); // 使用 ASCII 字符 5 进行填充
        }
        return paddedString.toString().getBytes();
        // 字符串后面添加 ASCII 字符0作为填充
        // return Arrays.copyOf(data, newSize);
    }

    public static void main(String[] args) throws Exception {

        String content = "2024-10-01";
        System.out.println("====================[自动生成秘钥对]====================");
        String aesKey = autoGenerateKey();
        System.out.println("aesKey = " + aesKey);
        String encryptText = encrypt(content, aesKey, "1234567890123456");
        System.out.println("encryptText = " + encryptText);
        String decryptText = decrypt(encryptText, aesKey,"1234567890123456");
        System.out.println("decryptText = " + decryptText);
        System.out.println("====================[根据自定义字符串生成秘钥对]====================");
        String keyStr = "712cmccmdh4l8h04"; //注意自定义的key长度必须为16，这里暂时没有进行补位运算，主要是与前端计算的不一致
        String iv = "yvz2pw9ejb8cybpu";
        System.out.println("keyStr = " + keyStr);
        String encryptText1 = encrypt(content, keyStr,iv);
        System.out.println("encryptText1 = " + encryptText1);
        String decryptText1 = decrypt(encryptText1, keyStr,iv);
        System.out.println("decryptText1 = " + decryptText1);

        System.out.println("==============================================================");


        System.out.println("BASE64Utils.decodeBase64(\"HTJdoSZ+NNK/08sRBEmb7w==\") = " + BASE64Utils.decodeBase64("HTJdoSZ+NNK/08sRBEmb7w=="));

    }

}
